import 'dart:convert';

import 'package:backend.core/core/domain/utils/either_extension.dart';
import 'package:backend.core/core/infrastructure/helpers/request_helpers.dart';
import 'package:backend.core/core/domain/entities/api/web/api_web_purchased_subscription.dart';
import 'package:backend.purchases/domain/use_cases/cancel_web_purchased_subscription/use_case.dart';
import 'package:backend.purchases/infrastructure/dtos/api/web/api_web_purchased_subscription_dto.dart';
import 'package:shelf/shelf.dart';

part 'dtos/successful_response_dto.dart';

abstract class WebPurchasedSubscriptionCancellationController {
  Future<Response> call(Request request);
}

class WebPurchasedSubscriptionCancellationControllerImpl
    implements WebPurchasedSubscriptionCancellationController {
  const WebPurchasedSubscriptionCancellationControllerImpl({
    required CancelWebPurchasedSubscription cancelWebPurchasedSubscription,
  }) : _cancelWebPurchasedSubscription = cancelWebPurchasedSubscription;

  final CancelWebPurchasedSubscription _cancelWebPurchasedSubscription;

  @override
  Future<Response> call(Request request) async {
    final requestBody = await parseJsonRequestBody(
      request: request,
    );

    final accessTokenClaim = extractAccessTokenClaim(
      request: request,
    );

    final String originalTransactionId;

    try {
      originalTransactionId = requestBody['original_transaction_id'];
    } catch (e) {
      return Response(
        400,
        body: 'Original transaction id is invalid.',
      );
    }

    final failureOrPurchasedSubscription = await _cancelWebPurchasedSubscription(
      userId: accessTokenClaim.userId,
      originalTransactionId: originalTransactionId,
    );

    if (failureOrPurchasedSubscription.isLeft()) {
      final failure = failureOrPurchasedSubscription.asLeft();

      if (failure is NotFoundWebPurchasedSubscriptionCancellationFailure) {
        return Response(404);
      }

      throw UnimplementedError();
    }

    final purchasedSubscription = failureOrPurchasedSubscription.asRight();

    final successfulResponseDto = _SuccessfulResponseDto(
      purchasedSubscription: purchasedSubscription,
    );

    final successfulResponseJson = successfulResponseDto.toJson();
    final successfulResponseString = jsonEncode(successfulResponseJson);

    return Response(
      200,
      body: successfulResponseString,
      headers: {
        'Content-Type': 'application/json',
      },
    );
  }
}
